#include "io.h"
#include "drv_gpio.h"


#define readl(addr)           (*(volatile unsigned int *)(addr))
#define writel(value,addr)    (*(volatile unsigned int *)(addr) = (value))

int gpio_set_func(enum gpio_port port, enum gpio_pin pin, rt_uint8_t func){
    rt_uint32_t addr;
    rt_uint32_t offset;
    rt_uint32_t data;

    addr = GPIOn_CFG_ADDR(port) + (pin / 8) * 4;
    offset = (pin % 8) * 4;

    data = readl(addr);
    data &= ~(0x7 << offset);
    data |= func << offset;
    writel(data, addr);
   
    return RT_EOK;
}

int gpio_set_value(enum gpio_port port, enum gpio_pin pin, rt_uint8_t value){
    rt_uint32_t addr;
    rt_uint32_t offset;
    rt_uint32_t data;
    addr = GPIOn_DATA_ADDR(port);
    offset = pin;

    data = readl(addr);
    data &= ~(0x1 << offset);
    data |= value << offset;
    writel(data, addr);
    return RT_EOK;
}

int gpio_get_value(enum gpio_port port, enum gpio_pin pin){
    rt_uint32_t addr;
    rt_uint32_t offset;
    rt_uint32_t data;

    addr = GPIOn_DATA_ADDR(port);
    offset = pin;

    data = readl(addr);

    return (data >> offset) & 0x01;
}

int gpio_set_pull_mode(enum gpio_port port,  enum gpio_pin pin, enum gpio_pull pull){
    rt_uint32_t addr;
    rt_uint32_t offset;
    rt_uint32_t data;

    addr = GPIOn_PUL_ADDR(port);
    addr += pin > GPIO_PIN_15 ? 0x4 : 0x0;
    offset = (pin & 0xf) << 1;

    data = readl(addr);
    data &= ~(0x3 << offset);
    data |= pull << offset;
    writel(data, addr);

    return RT_EOK;
}

int gpio_set_drive_level(enum gpio_port port, enum gpio_pin pin, enum gpio_drv_level level){
    volatile rt_uint32_t addr;
    rt_uint32_t offset;
    rt_uint32_t data;

    addr = GPIOn_DRV_ADDR(port);
    addr += pin > GPIO_PIN_15 ? 0x4 : 0x0;
    offset = (pin & 0xf) << 1;

    data = readl(addr);
    data &= ~(0x3 << offset);
    data |= level << offset;
    writel(data, addr);

    return RT_EOK;
}



